import axios from "axios";
import store from "@/store";
import qs from "qs";

import { Message } from "element-ui";

import router from "@/router";

const request = axios.create({
  timeout: 20000,
  // baseURL:
  // headers:
});

// 根据不同的域名知道
function getBaseURL(url) {
  if (url.startsWith("/boss")) {

    // 
    return "http://localhost:9002";
  } else if (url.startsWith("/front")) {

    // 
    return "http://localhost:9002";
  }
}

function redirectLogin() {
  router.push({
    name: "login",
    query: {
      redirect: router.currentRoute.fullPath,
    },
  });
}

// 前端对路由的拦截器。根据不同的项目前端匹配不同的域名。
request.interceptors.request.use(function (config) {
  console.log(config.url);
  config.baseURL = getBaseURL(config.url);
  // 在同一拦截器的位置进行设置token处理。
  const { user } = store.state;
  if (user && user.access_token) {
    config.headers.Authorization = user.access_token;
  }
  return config;
});

// 避免多次刷新token
let isRefreshing = false;

// 响应的拦截器。
request.interceptors.response.use(
  // 状态码为2xxx调用的方法。
  function (response) {
    console.log("成功响应了", response);
    return response;
  },
  function (error) {
    // 参考文档：https://github.com/axios/axios#handling-errors
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      // 处理401的情况。
      let errorMessage = "";
      const { status } = error.response;
      if (status === 400) {
        errorMessage = "请求参数错误！";
      } else if (status === 401) {
        errorMessage = "Token 无效！";

        // 1.没有token信息  query方便登录后回到失效的页面。
        if (!store.state.user) {
          redirectLogin();
          // return 让方法及时结束。
          return Promise.reject(error);
        }

        // 2.有token信息但是无效。
        // 发送请求获取新的token
        // console.log('------refresh_token------');
        // console.log(qs.stringify(store.state.user.refresh_token));
        // console.log('------refresh_token------');

        // 检测查看是否存在已经发送的请求。
        if (isRefreshing) {
          //  将因为token失效不能访问的连接，存储到请求列表中。使用数组进行存值。
          // 传入的匿名函数，在更新完token后全部发送一遍。
          requests.push(() => request(error.config))

          return;
        }

        // 存储是否正在更新token。
        isRefreshing = true;
        
        // 存储等待token刷新而挂起的请求。
        let requests = [];
        return request({
          method: "POST",
          url: "/front/user/refresh_token",
          data: qs.stringify({
            refreshtoken: store.state.user.refresh_token,
          }),
          // 如果刷新失败需要跳转到登录页结束。
        })
          .then((res) => {
            console.log(res);
            if (res.data.state != 1) {
              // 清除无效的用户信息
              store.commit("setUser", null);
              redirectLogin();
              return Promise.reject(error);
            }
            // 如果刷新成功了更新token信息
            store.commit("setUser", res.data.content);
            // 成功刷新token之后，调用之前失败的请求。程序不再执行：return Promise.reject(error);
            // return request(error.config);  不再是发送单个，而是发送所有的失败的请求。
            requests.forEach(xxx => xxx());
            // 发送完毕后清除挂起的请求。
            requests = []; 
            // 本次请求不再requests中
            return request(error.config);
          })
          .catch((err) => {
            console.log(err);
          })
          // 请求发送完毕，需要将变量变为false，方便下一次的请求。
          .finally((isRefreshing = false));
      } else if (status === 403) {
        errorMessage = "没有权限，请联系系统管理员！";
      } else if (status === 404) {
        errorMessage = "请求资源不存在！";
      } else if (status >= 500) {
        errorMessage = "服务端错误，请联系管理员！";
      }
      Message.error(errorMessage);
    } else if (error.request) {
      // The request was made but no response was received 请求发送成功但是没有响应。
      // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
      // http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // 意料之外的错误。。
      // Something happened in setting up the request that triggered an Error
      console.log("Error", error.message);
    }
    // 将本次请求的错误对象继续向后抛出，让接收响应的处理函数进行操作。
    return Promise.reject(error);
  }
);

export default request;
